home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
HENSA
/
GRAPHICS
/
SPRite_TOOLS.ARC
/
c
/
spr_pal
< prev
next >
Wrap
Text File
|
1998-04-03
|
15KB
|
575 lines
/************************************************************************
* *
* spr_pal.c *
* *
* Makes a sprite consisting of a !Paint style *
* palette for sprites <= 8 BPP, or for >8 BPP *
* a sprite with the colours sorted on value *
* *
* Supports histogram option for all BPP *
* *
* Version 2.12 (08-Mar-1994) *
* *
* (C) 1993/4 DEEJ Technology PLC *
* *
************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "io.h"
#include "sprite.h"
#include "process.h"
#include "palette.h"
#define SIZE 16 /* palette sprite cell size */
#define HIST_MAX 1024 /* maximum number of bars in histogram */
#define HEIGHT_MAX 768 /* maximum height of histogram sprite */
/* globals */
FILE *inf, *outf, *errf;
int bytes;
int total;
char string[256];
/*
* Colour hue
* 1 256 512 768 1024 1280 1536
* R Y G C B M R
* greys are 0
*/
int hue(uint rgb)
{
int add;
int b = (rgb >> 24) &0xFF;
int g = (rgb >> 16) &0xFF;
int r = (rgb >> 8) &0xFF;
int c1 = 0;
int c2 = 0;
/* exclude grey levels */
if(r==g && r==b) return(0);
/* find one/two dominant components */
if((r>=g && g>=b) || (g>=r && r>=b))
{
c1 = r - b;
c2 = g - b;
add = 256;
}
else
{
if((g>=b && b>=r) || (b>=g && g>=r))
{
c1 = g - r;
c2 = b - r;;
add = 768;
}
else
{
/* must be */
/*
if((b>=r && r>=g) || (r>=b && b>=g))
*/
{
c1 = b - g;
c2 = r - g;
add = 1280;
}
}
}
/* scale components so largest is full range */
if(c1 > c2)
{
c2 = (c2*255)/c1;
c1 = 255;
}
else
{
c1 = (c1*255)/c2;
c2 = 255;
}
return( ((c2-c1) + add) % 1536 );
}
/*
* qsort comparison function for 8-32 BPP pixels
* and pointers to hist_entry structures (bytes=8)
*/
int compar(const void *vptr1, const void *vptr2)
{
static int count = 0;
uchar *ptr1 = (uchar*)vptr1;
uchar *ptr2 = (uchar*)vptr2;
uint r,g,b;
uint val1, val2;
int int1, int2;
int hue1, hue2;
switch(bytes)
{
case 2:
val1 = ptr1[0] + (ptr1[1] << 8);
r = (val1 >> 0) &0x1F; r = (r<<3) | (r>>2);
g = (val1 >> 5) &0x1F; g = (g<<3) | (g>>2);
b = (val1 >> 10) &0x1F; b = (b<<3) | (b>>2);
val1 = (b<<24) | (g<<16) | (r<<8);
val2 = ptr2[0] + (ptr2[1] << 8);
r = (val2 >> 0) &0x1F; r = (r<<3) | (r>>2);
g = (val2 >> 5) &0x1F; g = (g<<3) | (g>>2);
b = (val2 >> 10) &0x1F; b = (b<<3) | (b>>2);
val2 = (b<<24) | (g<<16) | (r<<8);
break;
case 4:
val1 = endian(LE, *(uint*)vptr1);
val2 = endian(LE, *(uint*)vptr2);
/* convert xxBBGGRR to BBGGRR00 */
val1 = val1<<8;
val2 = val2<<8;
break;
case 8:
val1 = (*((hist_entry**)vptr1))->value;
val2 = (*((hist_entry**)vptr2))->value;
break;
}
if((++count % (total/50))==0) fputc('.',errf);
hue1 = hue(val1);
hue2 = hue(val2);
if(hue1==hue2)
{
int1 = intensity(val1);
int2 = intensity(val2);
return(int1-int2);
}
else
{
return(hue1-hue2);
}
}
/*
* Make !Paint style palette sprite
* with different size but same BPP & palette
*/
void palette_sprite(spr_info_str *spr)
{
int X,Y;
int x1,y1;
int x2,y2;
int val;
switch(spr->bpp)
{
case 1: X = 2; Y = 1; break;
case 2: X = 2; Y = 2; break;
case 4: X = 4; Y = 4; break;
case 8: X = 16; Y = 16; break;
}
spr->X = X * SIZE;
spr->Y = Y * SIZE;
spr->Xasp = 1;
spr->Yasp = 1;
fill_info(spr);
alloc_spr_data(spr);
memset(spr->spr_data, 0, spr->line_size*spr->Y);
/* make !PAINT type palette grid */
progress_start(string);
for(y1=0; y1<Y; y1++)
for(x1=0; x1<X; x1++)
{
/* palette entry index */
val = y1*Y+x1;
for(y2=1; y2<(SIZE-1); y2++)
for(x2=1; x2<(SIZE-1); x2++)
{
write_pixel_val(spr,x1*SIZE+x2,y1*SIZE+y2,val);
}
progress(y1*Y+x1,X*Y);
}
write_sprite(spr, outf);
}
/*
* Read sprite data and sort to give rougth palette display
*/
void sort_sprite(spr_info_str *spr)
{
int x, y;
int line_size;
uchar *line;
/* set up globals */
bytes = spr->pix/8; /* bytes per pixel */
total = spr->X*spr->Y*15; /* approx no. compares */
/* sort cannot handle 3 byte values, so convert to 24/32 BPP */
if(spr->pix == 24)
{
line_size = spr->line_size;
spr->pix = 32;
fill_info(spr);
}
alloc_spr_data(spr);
/* cannot read sprite data as is - must remove line padding */
switch(bytes)
{
case 2:
case 4:
for(y=0; y<spr->Y; y++)
{
fread(spr->spr_data + (y*spr->X*bytes),
spr->line_size, 1, inf);
}
break;
case 3:
/* must be expanded to 32 BPP for sorting */
if((line=malloc(line_size))==0)
{
fprintf(stderr,"Unable to allocat line buffer\n");
exit(1);
}
for(y=0; y<spr->Y; y++)
{
fread(line, line_size, 1, inf);
for(x=0; x<spr->X; x++)
{
spr->spr_data[(((y*spr->X)+x)*4)+0] = line[x*3+0];
spr->spr_data[(((y*spr->X)+x)*4)+1] = line[x*3+1];
spr->spr_data[(((y*spr->X)+x)*4)+2] = line[x*3+2];
spr->spr_data[(((y*spr->X)+x)*4)+3] = 0;
}
}
bytes = 4;
break;
default:
fprintf(errf,"Sorting not supported for %d BPP\n",spr->bpp);
exit(2);
break;
}
progress_start(string);
qsort((void*)spr->spr_data, spr->X*spr->Y, bytes, compar);
write_sprite_header(spr, outf);
/* write out with line padding */
for(y=0; y<spr->Y; y++)
{
fwrite(spr->spr_data + (y * spr->X * bytes),
spr->line_size, 1, outf);
}
}
/*
* produce a histogram sprite depicting
* colour use of original sprites data
*/
void histogram_sprite(spr_info_str *spr, hist_info *h)
{
hist_entry *entry_ptr;
hist_entry **index;
int x, y, x2, y2;
int xsize, ysize;
int xstep, ystep, yinc;
int filter;
int average;
uint bg;
pix_str col;
pix_str *c;
/* decide on a filter threshold to give < HIST_MAX pixels accross */
filter = 0;
xsize = h->colours;
if(xsize > HIST_MAX)
{
filter = 1;
xsize = h->more1;
}
if(xsize > HIST_MAX)
{
filter = 10;
xsize = h->more10;
}
if(xsize > HIST_MAX)
{
filter = 100;
xsize = h->more100;
}
if(xsize<h->more_frac && (xsize<256 || h->more_frac<HIST_MAX))
{
filter = h->fraction;
xsize = h->more_frac;
}
/* if small number of colours increase bar spacing */
if(xsize <= (HIST_MAX/4))
{
if(xsize <= (HIST_MAX/8))
xstep = 4;
else
xstep = 2;
}
else
{
xstep = 1;
}
/* build index table for sorting from filtered histogram */
if((index=(hist_entry**)malloc(xsize*sizeof(hist_entry_ptr)))==0)
{
fprintf(stderr,"Unable to allocate index table\n");
exit(1);
}
x = 0;
average = 0;
entry_ptr = h->list_head;
while(entry_ptr != 0)
{
if(entry_ptr->count > filter)
{
index[x++] = entry_ptr;
average += entry_ptr -> count;
}
entry_ptr = entry_ptr->next;
}
average /= xsize;
/* integrity check */
if(x != xsize)
{
fprintf(stderr, "Filtered count disagress with precalculated (%d,%d)\n", x, xsize);
exit(2);
}
/*
* determine Y scale to give height < HEIGHT_MAX
* use maximum use from histogram and the average use
* AFTER filtering (rather than value from histogram)
*/
if(h->max_use > average*8)
{
ysize = average*8;
}
else
{
ysize = h->max_use;
}
ystep = 1;
if(ysize > HEIGHT_MAX)
{
ystep = (ysize + HEIGHT_MAX-1)/HEIGHT_MAX;
ysize /= ystep;
}
fprintf(errf,"Filter : %d\n",filter);
fprintf(errf,"Num of bars : %d\n",xsize);
fprintf(errf,"Y scale : 1:%d\n",ystep);
spr->X = xsize*xstep;
spr->Y = ysize;
spr->Xasp = 1;
spr->Yasp = 1;
/* sort index table */
/* set up globals */
bytes = 8; /* comparison type flag */
total = xsize*20; /* approx no. compares */
sprintf(string, "Sorting :");
progress_start(string);
qsort((void*)index, xsize, sizeof(hist_entry_ptr), compar);
progress_finish();
/* make sprite of appropriate size */
fill_info(spr);
alloc_spr_data(spr);
/* choose background colour and clear sprite */
col.red = 0;
col.green = 0;
col.blue = 0;
c = closest_rgb(spr, &col);
switch(spr->bpp)
{ /* convert colour number to whole byte */
case 1: bg = c->value * 0xFF; break;
case 2: bg = c->value * 0x55; break;
case 4: bg = c->value * 0x11; break;
case 8: bg = c->value; break;
default: bg = 0; break;
}
memset(spr->spr_data, bg, spr->line_size*spr->Y);
/* plot histogram bars on sprite */
sprintf(string,"Generating palette sprite:");
progress_start(string);
entry_ptr = h->list_head;
for(x=0; x<xsize; x++)
{
col.value = index[x]->value;
col.blue = (col.value >> 24) & 0xFF;
col.green = (col.value >> 16) & 0xFF;
col.red = (col.value >> 8) & 0xFF;
c = closest_rgb(spr, &col);
/* correct for background colour bar */
if(c->value == (int)bg)
{
col.red = col.red ^ 0xFF;
col.green = col.green ^ 0xFF;
col.blue = col.blue ^ 0xFF;
c = closest_rgb(spr, &col);
yinc = 2;
}
else
{
yinc = 1;
}
x2 = xstep/2 + x*xstep;
if((index[x]->count/ystep) <= 1)
{
write_pixel_val(spr, x2, spr->Y-1, c->value);
}
else
{
y2 = index[x]->count/ystep;
y2 = y2>=ysize ? ysize-1 : y2;
for(y=0; y<y2; y+=yinc)
{
write_pixel_val(spr, x2, spr->Y-y-1, c->value);
}
}
progress(x, xsize);
}
write_sprite(spr, outf);
}
int main(int argc, char **argv)
{
BOOL histogram = FALSE;
hist_info *hist;
spr_info_str spr;
if(argc>1 && argv[1][0]=='-')
{
if(argv[1][1] == 'h')
{
histogram = TRUE;
}
else
{
fprintf(errf,"Unrecognised flag '%s'\n",argv[1]);
return(1);
}
argc--; argv++;
}
file_args(argc, argv, &inf, &outf, &errf);
/* read sprite from file */
read_sprite_header(&spr, inf);
sprintf(string,"Generating palette sprite:");
if(histogram)
{
/* read sprite & build histogram of colour usage */
alloc_spr_data(&spr);
fread(spr.spr_data, spr.line_size, spr.Y, inf);
hist = build_histogram(&spr);
/* free orginal sprite data and make a histogram image */
free((void*)spr.spr_data);
histogram_sprite(&spr, hist);
}
else
{
if(spr.bpp <= 8)
{
palette_sprite(&spr);
}
else
{
sort_sprite(&spr);
}
}
progress_finish();
fclose(inf);
fclose(outf);
fclose(errf);
}